package com.leilei.entity;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;

import java.sql.PreparedStatement;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.Set;


/**
 * @author: lei
 * @date: 2025-05-20 18:06
 * @desc: MyBatis 插件：在执行插入/更新前对实体对象中标记字段进行 SM4 加密
 */
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)})
public class Sm4EncryptInterceptor implements Interceptor {

    private final EncryptProcessor processor;

    public Sm4EncryptInterceptor(EncryptProcessor processor) {
        this.processor = processor;
    }


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取 ParameterHandler，进而获取真实的参数对象
        ParameterHandler handler = (ParameterHandler) invocation.getTarget();
        Object paramObj = handler.getParameterObject();
        if (paramObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> paramMap = (Map<String, Object>) paramObj;

            // 优先尝试获取 MyBatis-Plus 标准命名下的实体
            Object entity = null;
            if (paramMap.containsKey("et")) {
                entity = paramMap.get("et");
            } else if (paramMap.containsKey("param1")) {
                entity = paramMap.get("param1");
            }
            if (entity != null) {
                processor.process(entity, EncryptProcessor.Mode.ENCRYPT);
            } else {
                // 兜底策略：找 Map 中第一个用户定义的实体（排除基本类型、Map等）
                Set<Map.Entry<String, Object>> entries = paramMap.entrySet();
                for (Map.Entry<String, Object> entry : entries) {
                    Object value = entry.getValue();
                    String key = entry.getKey();
                    if (value == null) {
                        continue;
                    }
                    if (isSimpleType(value.getClass()) && !"ew".equals(key) && !"wrapper".equalsIgnoreCase(key)) {
                        processor.process(value, EncryptProcessor.Mode.ENCRYPT);
                        // 找到一个可能的实体后就 break，避免重复加密
                        break;
                    }
                }

            }
        } else {
            processor.process(paramObj, EncryptProcessor.Mode.ENCRYPT);
        }
        return invocation.proceed();
    }
    private boolean isSimpleType(Class<?> clazz) {
        return clazz.isPrimitive() ||
                clazz.equals(String.class) ||
                Number.class.isAssignableFrom(clazz) ||
                Date.class.isAssignableFrom(clazz) ||
                clazz.equals(Boolean.class) ||
                clazz.equals(Character.class) ||
                Map.class.isAssignableFrom(clazz);
    }

    @Override
    public Object plugin(Object target) {
        // 将拦截器应用到目标对象
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以通过配置文件注入 sm4Key，这里省略
    }
}
